#include <iostream>
#include <string>
#include <pthread.h>
#include <unistd.h>

// 生产者消费者模型
using namespace std;

#define TNUM 4
typedef void (*func_t)(const std::string& name, pthread_mutex_t* pmtx, pthread_cond_t* pcond);
volatile bool quit = false; // 退出信号，默认为false

class ThreadData
{
public:
    ThreadData(const std::string& name, func_t func, pthread_mutex_t* pmtx, pthread_cond_t* pcond)
        : _name(name), _func(func), _pmtx(pmtx), _pcond(pcond) {}

public:
    // 成员变量
    string _name;
    func_t _func;
    pthread_mutex_t* _pmtx;
    pthread_cond_t* _pcond;
};


void func1(const string& name, pthread_mutex_t* pmtx, pthread_cond_t* pcond)
{
    while(!quit)
    {
        // wait 需要在加锁和解锁之间
        pthread_mutex_lock(pmtx); // 加锁
        //
        pthread_cond_wait(pcond, pmtx); // 默认该线程在执行时，wait 代码被执行，当前线程会被立即阻塞
        cout << name << "running <-> 播放" << endl;
        pthread_mutex_unlock(pmtx); // 解锁
    }
}

void func2(const string& name, pthread_mutex_t* pmtx, pthread_cond_t* pcond)
{
    while(!quit)
    {
        // 加锁 等待 解锁
        pthread_mutex_lock(pmtx);
        pthread_cond_wait(pcond, pmtx);
        cout << name << "running <-> 下载" << endl;
        pthread_mutex_unlock(pmtx);
    }
}

void func3(const string& name, pthread_mutex_t* pmtx, pthread_cond_t* pcond)
{
   while(!quit)
   {
       // 加锁 等待 解锁
       pthread_mutex_lock(pmtx);
       pthread_cond_wait(pcond, pmtx);
       cout << name << "running <-> 刷新" << endl;
       pthread_mutex_unlock(pmtx);
   }
}

void func4(const string& name, pthread_mutex_t* pmtx, pthread_cond_t* pcond)
{
   while(!quit)
   {
       // 加锁 等待 解锁
       pthread_mutex_lock(pmtx);
       pthread_cond_wait(pcond, pmtx);
       cout << name << "running <-> 扫码用户信息" << endl;
       pthread_mutex_unlock(pmtx);
   }
}

// 线程入口函数
void* Entry(void *args)
{
    ThreadData* td = (ThreadData*)args; // 获取线程所需的数据
    td->_func(td->_name, td->_pmtx, td->_pcond);
    delete td;
    return nullptr;
}

int main()
{
    // 初始化互斥锁mtx 和 条件变量cond
    pthread_mutex_t mtx;
    pthread_cond_t cond;
    pthread_mutex_init(&mtx, nullptr);
    pthread_cond_init(&cond, nullptr);

    // 创建 TNUM 个线程，并将每个线程相关的函数和共享的互斥锁、条件变量传递给线程的入口函数 Entry。
    // 每个线程都有一个不同的名称和要执行的函数（func）
    pthread_t tids[TNUM];
    func_t funcs[TNUM] = {func1, func2, func3, func4};
    for (int i = 0; i < TNUM; i++)
    {
        string name = "Thread ";
        name += to_string(i+1);
        ThreadData *td = new ThreadData(name, funcs[i], &mtx, &cond);
        pthread_create(tids + i, nullptr, Entry, (void*)td);
    }

    // 调用 pthread_cond_signal 函数向条件变量发送信号，通知等待该条件的线程可以继续运行
    int cnt = 10;
    while(cnt)
    {
        cout << "resume thread run code ...." << cnt-- << endl; // 打印输出当前计数器的值，并将计数器减一
        pthread_cond_signal(&cond);
        // pthread_cond_broadcast(&cond);
        sleep(1);
    }

    // 代码设置 quit 标志为 true，
    // 调用 pthread_cond_broadcast 函数向所有等待该条件的线程广播信号
    cout << "ctrl done" << endl;
    quit = true;
    pthread_cond_broadcast(&cond); // 唤醒所有等待在条件变量 cond 上的线程

    // 使用 pthread_join 等待所有线程的完成，然后销毁互斥锁和条件变量
    for(int i = 0; i < TNUM; i++)
    {
        pthread_join(tids[i], nullptr);
        std::cout << "thread: " << tids[i] << "quit" << std::endl;
    }

    pthread_mutex_destroy(&mtx);
    pthread_cond_destroy(&cond);

    return 0;
}
